package com.rizzo.infrastructure.component;

import com.rizzo.infrastructure.aop.ControllerAspect;
import com.rizzo.infrastructure.dark.redis.RedisDarkLauncher;
import com.rizzo.infrastructure.domain.Application;
import com.rizzo.infrastructure.performance.redis.DirectRedisPerformanceMonitor;
import com.rizzo.infrastructure.quota.redis.RedisQuotaMonitor;
import com.rizzo.infrastructure.redis.cache.ApplicationRedisCachePrefix;
import com.rizzo.infrastructure.redis.cache.RedisCacheManager;
import com.rizzo.infrastructure.redis.config.RedisConfigManager;
import com.rizzo.infrastructure.redis.key.RedisKey;
import com.rizzo.infrastructure.redis.serializer.BitmapSerializer;
import com.rizzo.infrastructure.redis.serializer.LongSerializer;
import com.rizzo.infrastructure.redis.serializer.RedisKeySerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.core.context.SecurityContextHolderStrategy;

import javax.annotation.Resource;
import java.util.BitSet;
import java.util.Map;


@Configuration
public class ControllerComponent {

    @Resource
    private Environment environment;

    @Resource
    private RedisConnectionFactory redisConnectionFactory;

    @Resource
    private SecurityContextHolderStrategy securityContextHolderStrategy;

    @Resource(name = "cacheExpirations")
    private Map<String, Long> cacheExpirations;

    @Resource
    private Application application;

    @Resource(name = "defaultSystemConfigMap")
    private Map<String, Object> defaultSystemConfigMap;

    public
    @Bean(name = "redisTemplate")
    RedisTemplate redisTemplate() {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

    public
    @Bean(name = "bitmapRedisTemplate")
    RedisTemplate<RedisKey, BitSet> bitmapRedisTemplate() {
        RedisTemplate<RedisKey, BitSet> bitmapRedisTemplate = new RedisTemplate<RedisKey, BitSet>();
        bitmapRedisTemplate.setConnectionFactory(redisConnectionFactory);
        bitmapRedisTemplate.setKeySerializer(new RedisKeySerializer());
        bitmapRedisTemplate.setValueSerializer(new BitmapSerializer());
        return bitmapRedisTemplate;
    }

    public
    @Bean(name = "stringRedisTemplate")
    StringRedisTemplate stringRedisTemplate() {
        StringRedisTemplate redisTemplate = new StringRedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

    public
    @Bean(name = "cacheRedisTemplate")
    RedisTemplate<String, Object> cacheRedisTemplate() {
        RedisTemplate<String, Object> cacheRedisTemplate = new RedisTemplate<String, Object>();
        cacheRedisTemplate.setConnectionFactory(redisConnectionFactory);
        cacheRedisTemplate.setKeySerializer(new StringRedisSerializer());
        cacheRedisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return cacheRedisTemplate;
    }

    public
    @Bean(name = "longRedisTemplate")
    RedisTemplate<RedisKey, Long> longRedisTemplate() {
        RedisTemplate<RedisKey, Long> longRedisTemplate = new RedisTemplate<RedisKey, Long>();
        longRedisTemplate.setConnectionFactory(redisConnectionFactory);
        longRedisTemplate.setKeySerializer(new RedisKeySerializer());
        longRedisTemplate.setValueSerializer(new LongSerializer());
        return longRedisTemplate;
    }

    public
    @Bean(name = "redisKeyRedisTemplate")
    RedisTemplate<RedisKey, String> redisKeyRedisTemplate() {
        RedisTemplate<RedisKey, String> redisKeyRedisTemplate = new RedisTemplate<RedisKey, String>();
        redisKeyRedisTemplate.setConnectionFactory(redisConnectionFactory);
        redisKeyRedisTemplate.setKeySerializer(new RedisKeySerializer());
        redisKeyRedisTemplate.setDefaultSerializer(new StringRedisSerializer());
        return redisKeyRedisTemplate;
    }

    public
    @Bean(name = "redisQuotaMonitor")
    RedisQuotaMonitor redisQuotaMonitor() {
        return new RedisQuotaMonitor(application.getApplicationName(), longRedisTemplate(), securityContextHolderStrategy);
    }

//	public
//	@Bean(name = "loggingPerformanceMonitor")
//	LoggingPerformanceMonitor loggingPerformanceMonitor() {
//		LoggingPerformanceMonitor loggingPerformanceMonitor = new LoggingPerformanceMonitor();
//		loggingPerformanceMonitor.setPrefix(LogStatement.PERFORMANCE_PREFIX);
//		loggingPerformanceMonitor.setUseDynamicLogger(true);
//		loggingPerformanceMonitor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
//		return loggingPerformanceMonitor;
//	}

    public
    @Bean(name = "directRedisPerformanceMonitor")
    DirectRedisPerformanceMonitor directRedisPerformanceMonitor() {
        DirectRedisPerformanceMonitor directRedisPerformanceMonitor = new DirectRedisPerformanceMonitor();
        directRedisPerformanceMonitor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
        directRedisPerformanceMonitor.setApplication(application.getApplicationName());
        directRedisPerformanceMonitor.setRedisConfigManager(redisConfigManager());
        directRedisPerformanceMonitor.setPerformanceRedisTemplate(redisKeyRedisTemplate());
        return directRedisPerformanceMonitor;
    }

    public
    @Bean(name = "controllerAspect")
    ControllerAspect controllerAspect() {
        return new ControllerAspect(redisQuotaMonitor(), directRedisPerformanceMonitor(), redisDarkLauncher());
    }

    public
    @Bean(name = "cacheManager")
    RedisCacheManager redisCacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager(cacheRedisTemplate());
        redisCacheManager.setUsePrefix(true);
        redisCacheManager.setCachePrefix(new ApplicationRedisCachePrefix(application.getApplicationName()));
        redisCacheManager.setExpires(cacheExpirations);
        return redisCacheManager;
    }

    public
    @Bean(name = "redisConfigManager")
    RedisConfigManager redisConfigManager() {
        return new RedisConfigManager(redisKeyRedisTemplate(), application.getApplicationName(), defaultSystemConfigMap);
    }

    public
    @Bean(name = "redisDarkLauncher")
    RedisDarkLauncher redisDarkLauncher() {
        return new RedisDarkLauncher(application.getApplicationName(), redisKeyRedisTemplate(), securityContextHolderStrategy);
    }

}
